package com.foreveross.bsl.push.web;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.foreveross.bsl.common.utils.mapper.BeanMapper;
import com.foreveross.bsl.common.utils.web.QueryFilter;
import com.foreveross.bsl.common.utils.web.QuerySpecs;
import com.foreveross.bsl.common.utils.web.model.PageMustache;
import com.foreveross.bsl.common.utils.web.model.QueryModelHelper;
import com.foreveross.bsl.common.utils.web.model.SelectBoxModel;
import com.foreveross.bsl.common.utils.web.model.SortInfoModel;
import com.foreveross.bsl.mam.app.application.AppMainApplication;
import com.foreveross.bsl.mam.app.application.vo.AppMainVo;
import com.foreveross.bsl.push.application.AppChannelConfigService;
import com.foreveross.bsl.push.application.vo.AppChannelConfigVo;
import com.foreveross.bsl.push.form.AppChannelConfigForm;
import com.foreveross.bsl.push.form.AppChannelConfigForm.ApnsConfigForm;
import com.foreveross.bsl.push.form.AppChannelConfigForm.OpenfireConfigForm;
import com.foreveross.bsl.push.vo.BslAppChannelConfigVo;
import com.foreveross.bsl.push.web.AppIdKeyHelper.AppIdKeyPair;
import com.foreveross.bsl.system.application.ApplicationRegisterApplication;
import com.google.common.collect.Lists;

/**
 * 
 * @description app
 * 
 * @author Wangyi
 * @version v1.0
 * @version v2.0 add by Vector Ho 添加instant-push配置
 * 
 * @2013-7-4
 * 
 */
@Controller
@RequestMapping(value = "/push/config")
public class AppChannelConfigController extends PushBaseController {
    
	private static final String APNS_FORM = "apns";
	private static final String APNS_SANDBOX_FORM = "apns_sandbox";
	private static final String OPENFIRE_FORM = "openfire";
	private static final String INSTANT_FORM = "instant";

	@Inject
	private AppChannelConfigService configService;
	
	@Inject
	private AppMainApplication appService;
	
	@Inject
	private ApplicationRegisterApplication appRegClient;
	
	@Inject
	private AppIdKeyHelper appIdKeyHelper;

	@RequestMapping
	public String list(@RequestParam(value = "page", defaultValue = "1") int pageNumber,
			@RequestParam(value = "page.size", defaultValue = PAGE_SIZE) int pageSize, 
			@RequestParam(value="appId", required=false) String appId, 
			Model model, HttpServletRequest request) {
		
		String queryUrl="/push/config";
		QueryModelHelper queryHelper = new QueryModelHelper(queryUrl, new SelectBoxModel(), makeSortInfo());
		QuerySpecs querySpecs = queryHelper.populateQueryModel(model, request);
		
		QueryFilter qfAppId = querySpecs.getFilter("appId");
		String qAppId=null;
		if(qfAppId!=null){
			qAppId=qfAppId.getValue().toString();
			if(StringUtils.isNotBlank(qAppId)){
				String appKey=this.appRegClient.getAppKeyByAppId(qAppId);
				querySpecs.replaceFilter(qfAppId, QueryFilter.eq("appId", appKey));
			}
		}
		
		Page<AppChannelConfigVo> configs = this.configService.findBy(pageNumber, pageSize, querySpecs);
		model.addAttribute("configs", convertToBslConfigs(configs.getContent()));
		model.addAttribute("appId", appId);
		model.addAttribute("apps", this.makeAppSelectBoxModel(qAppId).getOptions());
		model.addAttribute("page", new PageMustache(configs, PAGINATION_SIZE));
		return "/push/configs";
	}
	
	private final SelectBoxModel makeAppSelectBoxModel(String appId){
		List<AppMainVo> apps = this.appService.findAll();
		SelectBoxModel sbm=new SelectBoxModel();
		sbm.addOption("", "所有应用", true);
		for(AppMainVo app : apps){
			sbm.addOption(app.getId(), app.getApp_name());
		}
		sbm.setOptionSelected(appId);
		return sbm;
	}
	
	private final SortInfoModel makeSortInfo(){
		SortInfoModel sim=new SortInfoModel();
		sim.setSortEntry("createTime", "创建时间", false);
		return sim;
	}
	
	private List<BslAppChannelConfigVo> convertToBslConfigs(List<AppChannelConfigVo> configs) {
		//TODO 可将结果加入缓存
		List<BslAppChannelConfigVo> bslConfigs = Lists.newArrayList();
		for(AppChannelConfigVo appCfg : configs){
			BslAppChannelConfigVo bslAppCfg = BeanMapper.map(appCfg, BslAppChannelConfigVo.class);
			bslAppCfg.setBslAppId(this.appRegClient.getAppIdByAppKey(appCfg.getAppId()));
			bslAppCfg.setBslAppName(bslAppCfg.getBslAppId());
			try{
				AppMainVo app = appService.getEntity(bslAppCfg.getBslAppId());
				if(app!=null)
					bslAppCfg.setBslAppName(app.getApp_name());
			} catch (Exception e){}
			bslConfigs.add(bslAppCfg);
		}
		return bslConfigs;
	}
	
	@RequestMapping(value = "delete")
	public String delete(@RequestParam("id") String appId, RedirectAttributes redirectAttributes){
		//FIXME 如果appId使用路径参数，类似com.csair.amp的appId，传过来只com.csair，难道是SpringMVC BUG?
		this.configService.removeConfig(appId);
		redirectAttributes.addFlashAttribute("message", "删除应用配置成功 ");
		return "redirect:/push/config";
	}

	/**
	 * [channelConfigsForm description]  重定向到 增加推送渠道相关配置页面
	 * @param  "appId"     [description]
	 * @param  appId       [description]
	 * @param  appKey      [description]
	 * @param  "create"    [description]
	 * @param  create      [description]
	 * @param  "formType"  [description]
	 * @param  formType    [description]
	 * @param  redirectUrl [description]
	 * @param  model       [description]
	 * @return             [description]
	 */
	@RequestMapping(value = "channel", method = RequestMethod.GET)
	public String channelConfigsForm(@RequestParam(value = "appId", required = false) @ModelAttribute("appId") String appId,
			@ModelAttribute("appKey") String appKey,
			@RequestParam(value = "create", required = false) boolean create,
			@RequestParam(value = "formType", defaultValue = "all") String formType,
			@ModelAttribute("redirect") String redirectUrl, Model model) {
		
		if (!create) { // 更新
			AppIdKeyPair pair = appIdKeyHelper.check(appId, appKey);
			appId=pair.getAppId();
			appKey=pair.getAppKey();
			AppMainVo app = this.appService.getEntity(appId);
			model.addAttribute("app", app);
			AppChannelConfigVo cfg = this.configService.getConfig(appKey);
			model.addAttribute("apns", cfg.getApnsConfig());
			model.addAttribute("apnsSandbox", cfg.getApnsSandboxConfig());
			model.addAttribute("openfire", cfg.getOpenfireConfig());
		} else { // 创建
			AppMainVo app = null;
			if(StringUtils.isEmpty(appId) && !StringUtils.isEmpty(appKey)) {
				appId = this.appRegClient.getAppIdByAppKey(appKey);
			}
			if(!StringUtils.isEmpty(appId)) {
				app = this.appService.getEntity(appId);
			}
			if(app != null) {
				model.addAttribute("app", app);
			} else {
				List<AppMainVo> apps = this.appService.findAll();
				model.addAttribute("apps", apps);
			}
		}

		model.addAttribute("create", create);
		model.addAttribute("redirect", redirectUrl);
		model.addAttribute("appId", appId);
		model.addAttribute("appKey", appKey);
		
		if (APNS_FORM.equals(formType)) {
			model.addAttribute("apnsForm", true);
		} else if (APNS_SANDBOX_FORM.equals(formType)) {
			model.addAttribute("apnsSandboxForm", true);
		} else if (OPENFIRE_FORM.equals(formType)) {
			model.addAttribute("openfireForm", true);
		} else if(INSTANT_FORM.equals(formType)) {
			model.addAttribute("instantForm", true);
		} else { // defaultValue = "all"
			model.addAttribute("apnsForm", true);
			model.addAttribute("apnsSandboxForm", true);
			model.addAttribute("openfireForm", true);
			model.addAttribute("instantForm", true);
		}
		return "/push/channel-configs-form";
	}

	/**
	 * [channelConfig description] 增加推送渠道相关配置
	 * @param  form               [description]
	 * @param  "redirect"         [description]
	 * @param  redirectUrl        [description]
	 * @param  redirectAttributes [description]
	 * @return                    [description]
	 * @throws IOException        [description]
	 */
	@RequestMapping(value = "channel", method = RequestMethod.POST)
	public String channelConfig(AppChannelConfigForm form,
			@RequestParam(value = "redirect", required = false) String redirectUrl, RedirectAttributes redirectAttributes)
			throws IOException {
		
		/*System.out.println("\n-------hyw-------\ninstant=" + (form.getInstant() == null) 
				+ ", openfire=" + form.getInstant() + " redirectUrl=" + redirectUrl);*/
		
		// tail -f /app/tomcat6/logs/catalina.out
		
		AppIdKeyPair pair = this.appIdKeyHelper.check(form.getAppId(), form.getAppKey());
		form.setAppId(pair.getAppId());
		form.setAppKey(pair.getAppKey());
		
		if(form.getApns() != null) {
			updateApnsConfig(form.getApns(), form.getAppKey(), false);
		}
		if(form.getApnsSandbox() != null) {
			updateApnsConfig(form.getApnsSandbox(), form.getAppKey(), true);
		}
		OpenfireConfigForm openfire = form.getOpenfire();
		if(openfire != null && !"".equals(openfire.getUsername())) {
			this.configService.setOpenfireConfig(form.getAppKey(), openfire.getUsername(), openfire.getPassword());
		} 
		if(form.getInstant() != null) {
			this.configService.setInstantConfig(form.getAppKey()); // 持久化node-push推送渠道 add by hyw 20140529
		}
		
		redirectAttributes.addAttribute("appId", form.getAppId());
		redirectAttributes.addAttribute("appKey", form.getAppKey());

		if (StringUtils.isEmpty(redirectUrl)) {
			String msg = form.isCreate() ? "配置信息新增成功" : "配置信息修改成功";
			redirectAttributes.addFlashAttribute("message", msg);
			return "redirect:/push/config";
		} else {
			return redirectUrl; // create push form
		}
	}
	
	/**
	 * [updateApnsConfig description] 更新apns配置
	 * @param  apnsForm    [description]
	 * @param  appKey      [description]
	 * @param  sandbox     [description]
	 * @throws IOException [description]
	 */
	private void updateApnsConfig(ApnsConfigForm apnsForm, String appKey, boolean sandbox) throws IOException{
		if(apnsForm!=null){
			if (apnsForm.getCertFile() != null && apnsForm.getCertFile().getSize() != 0) {
				InputStream certIs = null;
				try {
					certIs = apnsForm.getCertFile().getInputStream();
					configService.setApnsConfig(appKey, certIs, apnsForm.getCertFile().getOriginalFilename(), apnsForm.getCertPassword(), sandbox);
				} finally {
					IOUtils.closeQuietly(certIs);
				}
			} else {
				this.configService.updateApnsConfig(appKey, apnsForm.getCertPassword(), sandbox);
			}
		}
	}
}
